import { createPromise } from "./promise";

interface ifRunningPromise<T> {
    (...args: T[]): Promise<any>
}

/**
 * 提供执行不同处理过程的协程
 * 返回只有 resolve的方式，没有 reject的执行
 * @param pools 执行程序池子
 * @param threadNum 启动的执行协程数量
 * @param args 每个方法执行的时候使用相同的参数组
 */
export function execPools<T>(pools: ifRunningPromise<T>[], threadNum: number, ...args: any[]) {

    let running_thread: ifRunningPromise<T>[][] = [];
    for (let i = 0; i < threadNum; i++) {
        running_thread.push([]);
    }
    // 把内容水平分组
    for (let i = 0; i < pools.length; i++) {
        running_thread[i % threadNum].push(pools[i]);
    }

    return new Promise(function (resolve) {
        let count = 0;
        let succPool: number[] = [];
        let failPool: number[] = [];
        let results: any[] = [];
        for (let i = 0; i < threadNum; i++) {
            createPromise(exec(i, threadNum, running_thread[i], ...args))
                .then(function (result) {
                    failPool.push(...result.fail);
                    succPool.push(...result.succ);
                    if (result.results && result.results.length > 0) {
                        results.push(...result.results)
                    }
                })
                .finally(function () {
                    count++;
                    if (count >= threadNum) {
                        resolve({ succ: succPool, fail: failPool, results: results });
                    }
                })
        }
    })
}

async function exec<T>(theadIdx: number, threadNum: number, pools: ifRunningPromise<T>[], ...args: T[]) {
    let succ: number[] = [];
    let fail: number[] = [];
    let results: any[] = [];
    for (let i = 0; i < pools.length; i++) {
        let idx = theadIdx + i * threadNum;
        try {
            let result = await pools[i](...args);
            succ.push(idx);
            results.push(result);
        }
        catch (e) {
            fail.push(idx);
        }
    }

    return { succ: succ, fail: fail, results: results };
}

/**
 * 执行相同处理过程的协程
 * 返回只有 resolve的方式，没有 reject的执行
 * @param exec 执行方法
 * @param threadNum 协程数量
 * @param args 执行的数据池子
 */
export function execPools2<T>(exec: ifRunningPromise<T>, threadNum: number, ...args: T[]) {

    let running_thread: T[][] = [];
    for (let i = 0; i < threadNum; i++) {
        running_thread.push([]);
    }
    // 把内容水平分组
    for (let i = 0; i < args.length; i++) {
        running_thread[i % threadNum].push(args[i]);
    }

    return new Promise(function (resolve) {
        let count = 0;
        let succPool: number[] = [];
        let failPool: number[] = [];
        let results: any[] = [];
        for (let i = 0; i < threadNum; i++) {
            createPromise(exec2(i, threadNum, exec, ...running_thread[i]))
                .then(function (result) {
                    failPool.push(...result.fail);
                    succPool.push(...result.succ);
                    if (result.results && result.results.length > 0) {
                        results.push(...result.results)
                    }
                })
                .finally(function () {
                    count++;
                    if (count >= threadNum) {
                        resolve({ succ: succPool, fail: failPool, results: results });
                    }
                })
        }
    })
}

async function exec2(theadIdx: number, threadNum: number, run_exec: ifRunningPromise<any>, ...args: any[]) {
    let succ: number[] = []
    let fail: number[] = [];
    let results: any[] = [];
    for (let i = 0; i < args.length; i++) {
        let idx = theadIdx + i * threadNum;
        try {
            let result = await run_exec(args[i]);
            succ.push(idx);
            results.push(result);
        }
        catch (e) {
            fail.push(idx);
        }
    }

    return { succ: succ, fail: fail, results: results };
}